﻿using System.Text;

namespace Koala.Pro.Common
{
    public class Base64Util
    {
        protected static Base64Util s_b64 = new Base64Util();

        protected string m_codeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZbacdefghijklmnopqrstu_wxyz0123456789*-";

        protected string m_pad = "v";

        protected Dictionary<int, char> m_t1 = new Dictionary<int, char>();

        protected Dictionary<char, int> m_t2 = new Dictionary<char, int>();

        public string CodeTable
        {
            get
            {
                return m_codeTable;
            }
            set
            {
                if (value == null)
                {
                    throw new Exception("密码表不能为null");
                }
                if (value.Length < 64)
                {
                    throw new Exception("密码表长度必须至少为64");
                }
                ValidateRepeat(value);
                ValidateEqualPad(value, m_pad);
                m_codeTable = value;
                InitDict();
            }
        }

        public string Pad
        {
            get
            {
                return m_pad;
            }
            set
            {
                if (value == null)
                {
                    throw new Exception("密码表的补码不能为null");
                }
                if (value.Length != 1)
                {
                    throw new Exception("密码表的补码长度必须为1");
                }
                ValidateEqualPad(m_codeTable, value);
                m_pad = value;
                InitDict();
            }
        }

        public Base64Util()
        {
            InitDict();
        }

        public static string Encrypt(string input)
        {
            return s_b64.Encode(input);
        }

        public static string Decrypt(string input)
        {
            return s_b64.Decode(input);
        }

        public static Base64Util GetStandardBase64()
        {
            return new Base64Util
            {
                Pad = "=",
                CodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
            };
        }

        public string Encode(string source)
        {
            if (source == null || source == "")
            {
                return "";
            }
            StringBuilder stringBuilder = new StringBuilder();
            byte[] array = Encoding.UTF8.GetBytes(source);
            int num = array.Length % 3;
            int num2 = 3 - num;
            if (num != 0)
            {
                Array.Resize(ref array, array.Length + num2);
            }
            int num3 = (int)Math.Ceiling((double)array.Length * 1.0 / 3.0);
            for (int i = 0; i < num3; i++)
            {
                stringBuilder.Append(EncodeUnit(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]));
            }
            if (num != 0)
            {
                stringBuilder.Remove(stringBuilder.Length - num2, num2);
                for (int j = 0; j < num2; j++)
                {
                    stringBuilder.Append(m_pad);
                }
            }
            return stringBuilder.ToString();
        }

        protected string EncodeUnit(params byte[] unit)
        {
            int[] array = new int[4]
            {
            (unit[0] & 0xFC) >> 2,
            ((unit[0] & 3) << 4) + ((unit[1] & 0xF0) >> 4),
            ((unit[1] & 0xF) << 2) + ((unit[2] & 0xC0) >> 6),
            unit[2] & 0x3F
            };
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < array.Length; i++)
            {
                stringBuilder.Append(GetEC(array[i]));
            }
            return stringBuilder.ToString();
        }

        protected char GetEC(int code)
        {
            return m_t1[code];
        }

        public string Decode(string source)
        {
            if (source == null || source == "")
            {
                return "";
            }
            List<byte> list = new List<byte>();
            char[] array = source.ToCharArray();
            int num = array.Length % 4;
            if (num != 0)
            {
                Array.Resize(ref array, array.Length - num);
            }
            int num2 = source.IndexOf(m_pad);
            if (num2 != -1)
            {
                num2 = source.Length - num2;
            }
            int num3 = array.Length / 4;
            for (int i = 0; i < num3; i++)
            {
                DecodeUnit(list, array[i * 4], array[i * 4 + 1], array[i * 4 + 2], array[i * 4 + 3]);
            }
            for (int j = 0; j < num2; j++)
            {
                list.RemoveAt(list.Count - 1);
            }
            return Encoding.UTF8.GetString(list.ToArray());
        }

        protected void DecodeUnit(List<byte> byteArr, params char[] chArray)
        {
            int[] array = new int[3];
            byte[] array2 = new byte[chArray.Length];
            for (int i = 0; i < chArray.Length; i++)
            {
                array2[i] = FindChar(chArray[i]);
            }
            array[0] = (array2[0] << 2) + ((array2[1] & 0x30) >> 4);
            array[1] = ((array2[1] & 0xF) << 4) + ((array2[2] & 0x3C) >> 2);
            array[2] = ((array2[2] & 3) << 6) + array2[3];
            for (int j = 0; j < array.Length; j++)
            {
                byteArr.Add((byte)array[j]);
            }
        }

        protected byte FindChar(char ch)
        {
            return (byte)m_t2[ch];
        }

        protected void InitDict()
        {
            m_t1.Clear();
            m_t2.Clear();
            m_t2.Add(m_pad[0], -1);
            for (int i = 0; i < m_codeTable.Length; i++)
            {
                m_t1.Add(i, m_codeTable[i]);
                m_t2.Add(m_codeTable[i], i);
            }
        }

        protected void ValidateRepeat(string input)
        {
            for (int i = 0; i < input.Length; i++)
            {
                if (input.LastIndexOf(input[i]) > i)
                {
                    throw new Exception("密码表中含有重复字符：" + input[i]);
                }
            }
        }

        protected void ValidateEqualPad(string input, string pad)
        {
            if (input.IndexOf(pad) > -1)
            {
                throw new Exception("密码表中包含了补码字符：" + pad);
            }
        }
    }
}
